package com.mindata.blockchain.socket.DGL.queue;

import com.mindata.blockchain.ApplicationContextProvider;
import com.mindata.blockchain.block.block.Block;
import com.mindata.blockchain.block.block.DGLBlock;
import com.mindata.blockchain.common.Commonvalue;
import com.mindata.blockchain.core.event.DGLAddBlocksEvent;
import com.mindata.blockchain.socket.common.event.IntroAddBlockEvent;
import com.mindata.blockchain.socket.common.queue.base.AbstractVoteMsgQueue;
import com.mindata.blockchain.socket.pbft.msg.VoteMsg;
import com.mindata.blockchain.socket.pbft.queue.CommitMsgQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

/**
 * Confirm阶段的消息队列
 * 每个节点收到超过2f+1个不同节点（包括自己）的commit消息后，就认为该区块已经达成一致，进入committed状态，并将其持久化到区块链数据库中
 *
 * @author wuweifeng wrote on 2018/4/25.
 */
@Component
public class DGLCommitMsgQueue extends AbstractVoteMsgQueue {
    @Resource
    private CommitMsgQueue commitMsgQueue;
    @Resource
    private DGLPreMsgQueue dglPreMsgQueue;
    @Resource
    private Commonvalue commonvalue;
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    protected void deal(VoteMsg voteMsg, List<VoteMsg> voteMsgs) {
        logger.error("DGLCommitMsg  Deal ");
        String hash = voteMsg.getHash();
        //通过校验agree数量，来决定是否在本地生成Block
        logger.error("DGLCommitMsgQueue deal: hash = {}", hash);
        long count = voteMsgs.stream().filter(VoteMsg::isAgree).count();
        logger.error("DGL区块{} 的DGLCommit agree 数量:{}, 阈值: {}", voteMsg.getHash(), count, commonvalue.getGlobalAgreeSize());
        if (count >= commonvalue.getGlobalAgreeSize()) {
            // 不清晰
            logger.error("DGLCommit agree 数量足够了，添加DGLBlock");
            List<Block> blocks = dglPreMsgQueue.findByHash(hash);
            for (Block block : blocks) {
                if (block == null) {
                    return;
                }
            }
            //本地落地
            voteStateConcurrentHashMap.put(hash, true);

            DGLBlock dglBlock = dglPreMsgQueue.findPreMsgByHash(hash).getDglBlock();
//            logger.error("DGL Commit 发布IntroAddBlockEvent");
            ApplicationContextProvider.publishEvent(new IntroAddBlockEvent(dglBlock));
//            logger.warn("{}发布添加DGL区块事件", this);
        }
    }


    @Order(3)
    @EventListener(DGLAddBlocksEvent.class)
    public void blockGenerated(DGLAddBlocksEvent dglAddBlocksEvent) {
        logger.warn("{}开始生成本地dglblock order 3", this);
        DGLBlock block = (DGLBlock) dglAddBlocksEvent.getSource();
        clearOldBlockHash(block.getDglBlockHeader().getNumber());
    }
}
